Skip to content

Fix PDF document uploading#628

Merged
yingbull merged 2 commits into
develop/dogfishfrom
issue-600-upload-doc
Sep 25, 2025
Merged

Fix PDF document uploading#628
yingbull merged 2 commits into
develop/dogfishfrom
issue-600-upload-doc

Conversation

@sebastian-j-ibanez

@sebastian-j-ibanez sebastian-j-ibanez commented Sep 23, 2025

Copy link
Copy Markdown
Collaborator

Changes made

  • Refactor ManageDocument2Action.java.
    • Sanitise file names.
    • Additional security checks.
    • Dedicated error page.
  • Add saveDir in struts.xml.

Summary by Sourcery

Refactor core document management actions to enhance security, parameter validation, and error handling, sanitize filenames against path traversal, add a dedicated error page, and configure save directory in Struts.

New Features:

  • Add dedicated JSP error page for document management errors

Bug Fixes:

  • Return HTTP 404 when viewing a non-existent document and handle missing remote document content
  • Prevent orphaned database entries by returning error on file move failures
  • Reject directory traversal attempts via queueId or pdfDir parameters

Enhancements:

  • Sanitize uploaded and stored filenames to remove unsafe characters
  • Add security and null checks throughout document update, view, display, and upload flows
  • Consolidate method routing logic in execute() to require valid parameters and return 'error' otherwise
  • Improve logging for invalid parameters and exception scenarios

Build:

  • Add saveDir configuration in struts.xml

Documentation:

  • Introduce simple JSP error page for document management errors

@sebastian-j-ibanez sebastian-j-ibanez self-assigned this Sep 23, 2025
@sourcery-ai

sourcery-ai Bot commented Sep 23, 2025

Copy link
Copy Markdown

Reviewer's Guide

Refactor ManageDocument2Action and AddEditDocument2Action for enhanced security, input validation, and centralized error handling; introduce filename sanitization and path traversal prevention; add dedicated error.jsp and configure saveDir and error mapping in struts.xml.

File-Level Changes

Change Details Files
Centralized error handling with dedicated error page
  • Return "error" result on exceptions or invalid state in execute, documentUpdate, viewDocPage, display, and addIncomingDocument
  • Add error.jsp to display user-friendly document error messages
  • Map error result to error.jsp in struts.xml
ManageDocument2Action.java
error.jsp
struts.xml
Filename sanitization and path traversal prevention
  • Sanitize uploaded filenames using FilenameUtils and regex before saving or moving files
  • Validate queueId and pdfDir parameters to block directory traversal
  • Sanitize docFileFileName and fileName in AddEditDocument2Action methods
ManageDocument2Action.java
AddEditDocument2Action.java
Enhanced input validation and null checks
  • Check for missing or empty method/parameters before invoking documentUpdate
  • Validate documentId, demog, remoteDocument, and Document object presence with error logging
  • Handle NumberFormatException for numeric parameters and skip operations if invalid
ManageDocument2Action.java
Struts configuration for file upload directory
  • Add struts.multipart.saveDir property in struts.xml
  • Ensure uploaded files are stored in the configured directory
struts.xml

Possibly linked issues


Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@github-actions

github-actions Bot commented Sep 23, 2025

Copy link
Copy Markdown

Dependency Review

✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.

Snapshot Warnings

⚠️: No snapshots were found for the head SHA 42eba16.
Ensure that dependencies are being submitted on PR branches and consider enabling retry-on-snapshot-warnings. See the documentation for more information and troubleshooting advice.

Scanned Files

None

@sebastian-j-ibanez sebastian-j-ibanez added area: echart Related to eChart functionality type: security labels Sep 23, 2025
@sebastian-j-ibanez sebastian-j-ibanez force-pushed the issue-600-upload-doc branch 2 times, most recently from 59b948a to 25ae642 Compare September 24, 2025 16:05
@sebastian-j-ibanez sebastian-j-ibanez marked this pull request as ready for review September 24, 2025 16:07

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey there - I've reviewed your changes and they look great!

Prompt for AI Agents
Please address the comments from this code review:

## Individual Comments

### Comment 1
<location> `src/main/java/ca/openosp/openo/documentManager/actions/ManageDocument2Action.java:1038-1040` </location>
<code_context>
         fileName = newDoc.getFileName();
-        destFilePath = savePath + fileName;
+        // Sanitize the filename to match what the file system will actually create
+        String sanitizedFileName = fileName.replaceAll("[^a-zA-Z0-9._-]", "");
+        newDoc.setFileName(sanitizedFileName);
+        destFilePath = savePath + sanitizedFileName;
         String doc_no = "";

</code_context>

<issue_to_address>
**issue:** Sanitizing fileName may result in empty or invalid filenames.

If sanitization removes all characters, the filename may become empty, leading to file system errors or overwriting. Please add a check to ensure the result is non-empty and unique.
</issue_to_address>

### Comment 2
<location> `src/main/java/ca/openosp/openo/documentManager/actions/ManageDocument2Action.java:1056-1062` </location>
<code_context>
         boolean success = f1.renameTo(new File(destFilePath));
         if (!success) {
             log.error("Not able to move " + f1.getName() + " to " + destFilePath);
-            // File was not successfully moved
+            // File was not successfully moved - return error to prevent orphaned database entries
+            request.setAttribute("errorMessage", "Failed to save document file. Please try again.");
+            return "error";
         } else {

</code_context>

<issue_to_address>
**suggestion (bug_risk):** Returning "error" on file move failure may leave temporary files orphaned.

Add logic to delete or archive the temporary file if the move fails to avoid leaving orphaned files.

```suggestion
        boolean success = f1.renameTo(new File(destFilePath));
        if (!success) {
            log.error("Not able to move " + f1.getName() + " to " + destFilePath);
            // File was not successfully moved - attempt to delete temp file to prevent orphaned files
            boolean deleted = f1.delete();
            if (!deleted) {
                log.warn("Failed to delete temporary file: " + f1.getAbsolutePath());
            }
            request.setAttribute("errorMessage", "Failed to save document file. Please try again.");
            return "error";
        } else {
```
</issue_to_address>

### Comment 3
<location> `src/main/java/ca/openosp/openo/documentManager/actions/AddEditDocument2Action.java:250-253` </location>
<code_context>
             }
-            // original file name
-            String fileName1 = this.docFileFileName;
+            // sanitize the original file name first
+            String fileName1 = MiscUtils.sanitizeFileName(this.docFileFileName);

             EDoc newDoc = new EDoc(this.getDocDesc(), this.getDocType(), fileName1, "", this.getDocCreator(), this.getResponsibleId(), this.getSource(), 'A', this.getObservationDate(), "", "", this.getFunction(), this.getFunctionId());
</code_context>

<issue_to_address>
**suggestion (bug_risk):** Sanitizing the original file name may not guarantee uniqueness.

Appending a timestamp, UUID, or similar unique identifier to the sanitized file name will help prevent collisions when files with similar names are uploaded.

```suggestion
            // sanitize the original file name first
            String sanitizedFileName = MiscUtils.sanitizeFileName(this.docFileFileName);

            // append a unique identifier to the sanitized file name to prevent collisions
            String uniqueId = java.util.UUID.randomUUID().toString();
            String fileExtension = "";
            int extIndex = sanitizedFileName.lastIndexOf(".");
            if (extIndex > 0 && extIndex < sanitizedFileName.length() - 1) {
                fileExtension = sanitizedFileName.substring(extIndex);
                sanitizedFileName = sanitizedFileName.substring(0, extIndex);
            }
            String fileName1 = sanitizedFileName + "_" + uniqueId + fileExtension;

            EDoc newDoc = new EDoc(this.getDocDesc(), this.getDocType(), fileName1, "", this.getDocCreator(), this.getResponsibleId(), this.getSource(), 'A', this.getObservationDate(), "", "", this.getFunction(), this.getFunctionId());
```
</issue_to_address>

### Comment 4
<location> `src/main/java/ca/openosp/openo/documentManager/actions/AddEditDocument2Action.java:393` </location>
<code_context>
                 File docFile = this.getDocFile();
                 if (docFile != null && docFile.exists()) {
-                    fileName = this.docFileFileName;
+                    fileName = MiscUtils.sanitizeFileName(this.docFileFileName);
                     updateFileContent = true; // set update to true
                 }
</code_context>

<issue_to_address>
**suggestion:** Sanitization during editDocument may not match original naming conventions.

Verify that the file name sanitization here matches the approach used during document creation to prevent inconsistencies.

Suggested implementation:

```java
                    fileName = DocumentUtils.getSanitizedFileName(this.docFileFileName);

```

- If `DocumentUtils.getSanitizedFileName` is not the actual method used during document creation, replace it with the correct one.
- If the document creation logic uses a different utility or static method, ensure you import and use that method here.
- If the sanitization logic is inline or custom, refactor it into a reusable method and use it in both places.
</issue_to_address>

### Comment 5
<location> `src/main/webapp/documentManager/error.jsp:20-3` </location>
<code_context>
+            <h3><span class="glyphicon glyphicon-exclamation-sign"></span> Document Error</h3>
+            <p>
+                <%
+                String errorMessage = (String) request.getAttribute("errorMessage");
+                if (errorMessage != null) {
+                    out.print(errorMessage);
+                } else {
+                    out.print("An error occurred while processing the document. The document may not exist or there was a problem with the file upload.");
+                }
+                %>
+            </p>
+
</code_context>

<issue_to_address>
**🚨 issue (security):** Error message display may expose internal details to end users.

Review errorMessage content to prevent exposure of sensitive system information to users.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment thread src/main/webapp/documentManager/error.jsp Outdated
@sebastian-j-ibanez sebastian-j-ibanez changed the title Refactor ManageDocument2Action Fix PDF document uploading Sep 24, 2025
sourcery-ai[bot]
sourcery-ai Bot previously requested changes Sep 24, 2025

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

New security issues found

@sebastian-j-ibanez

Copy link
Copy Markdown
Collaborator Author

@D3V41 if you have a second, would you be able to test if this fixes the PDF issues on your end?

@sebastian-j-ibanez

Copy link
Copy Markdown
Collaborator Author

(Just rebased the branch to be in line with dogfish, changes remain the same)

@sebastian-j-ibanez sebastian-j-ibanez linked an issue Sep 25, 2025 that may be closed by this pull request
@yingbull yingbull merged commit 6df4de0 into develop/dogfish Sep 25, 2025
13 of 15 checks passed
@sebastian-j-ibanez sebastian-j-ibanez deleted the issue-600-upload-doc branch October 1, 2025 17:19
@sebastian-j-ibanez sebastian-j-ibanez restored the issue-600-upload-doc branch October 1, 2025 17:19
@sebastian-j-ibanez sebastian-j-ibanez deleted the issue-600-upload-doc branch October 1, 2025 17:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: echart Related to eChart functionality

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Cannot view PDF documents Can't upload documents from document manager

2 participants